package com.nnggstory.logs.websocket;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.nnggstory.logs.common.IServer;
import com.nnggstory.logs.logsocket.LogSLogModel;
import com.nnggstory.logs.webserver.SimpleWebServer;

public class WebSocketPushServer extends WebSocketServer implements IServer {
	public static final int DEFAULT_PORT = 1092;
	private static final Logger logger = LoggerFactory.getLogger(SimpleWebServer.class);
	
	private Map<WebSocket, WebClientSetModel> clientsMap = null;
	private Map<String, Object> serverContext = null;

	public WebSocketPushServer(int port) {
		super(new InetSocketAddress(port));
		clientsMap = new HashMap<WebSocket, WebClientSetModel>();
	}

	
	public WebSocketPushServer() {
		this(DEFAULT_PORT);
	}
	
	@Override
	public void onClose(WebSocket ws, int arg1, String arg2, boolean arg3) {
		logger.debug(ws + " CLOSE :" +arg1);
		clientsMap.remove(ws);
	}

	@Override
	public void onError(WebSocket arg0, Exception arg1) {
		
	}

	@Override
	public void onMessage(WebSocket pws, String message) {
		logger.debug("message:" + message);
		String[] messageArray = message.split(WebSocketProtocalConstants.SEPERATOR);
		String header = messageArray[0];
		String operation = messageArray[1];
		String param = null;
		if(messageArray.length > 2) {
			param = messageArray[2];
		}
		boolean hasHeader = WebSocketProtocalConstants.HEADER.equals(header);
		boolean hasOperation = operation != null && !"".equals(operation);
		if(hasHeader && hasOperation) {
			doOperation(pws, operation, param);
		} else {
			pws.send(WebSocketProtocalConstants.HEADER+WebSocketProtocalConstants.SEPERATOR+"INVALID REQUEST");
		}
	}

	@Override
	public void onOpen(WebSocket ws, ClientHandshake arg1) {
		logger.debug(ws + ":" +arg1);
		clientsMap.put(ws, new WebClientSetModel());
	}
	
	@SuppressWarnings("unchecked")
	private void doOperation(WebSocket pws, String operation, String param) {
		String addedInfo = null;
		if(WebSocketProtocalConstants.REQ_OPERATION_OPEN.equals(operation)) {
			clientsMap.get(pws).setShowFlag(true);
		}
		else if(WebSocketProtocalConstants.REQ_OPERATION_CLOSE.equals(operation)) {
			clientsMap.get(pws).setShowFlag(false);
		}
		else if(WebSocketProtocalConstants.REQ_OPERATION_SERVER_LIST.equals(operation)) {
			Iterator<Socket> it = ((Set<Socket>)serverContext.get("loggerClients")).iterator();
			
			addedInfo = "";
			while(it.hasNext()) {
				Socket s = it.next();
				addedInfo += s.toString();
				if(it.hasNext()) {
					addedInfo +="+";
				}
			}
		}
		else if(WebSocketProtocalConstants.REQ_OPERATION_ADD_SERVER.equals(operation)) {
			List<String> showList = clientsMap.get(pws).getShowLoglist();
			if(showList == null) {
				showList = new ArrayList<String>();
				clientsMap.get(pws).setShowLoglist(showList);
			}
			if(!showList.contains(param)) {
				showList.add(param);
			}
			
		}
		else if(WebSocketProtocalConstants.REQ_OPERATION_DEL_SERVER.equals(operation)) {
			List<String> showList = clientsMap.get(pws).getShowLoglist();
			if(showList == null) {
				showList = new ArrayList<String>();
				clientsMap.get(pws).setShowLoglist(showList);
			}
			showList.remove(param);
		}
		String sendMessage = WebSocketProtocalConstants.HEADER+WebSocketProtocalConstants.SEPERATOR+operation+WebSocketProtocalConstants.SEPERATOR+WebSocketProtocalConstants.RES_OPERATION_OK;
		if(addedInfo != null && !"".equals(addedInfo)) {
			sendMessage += WebSocketProtocalConstants.SEPERATOR + addedInfo;
		}
		pws.send(sendMessage);
	}
	
	public void pushLog(Socket logSocket, LogSLogModel logModel) {
		Iterator<WebSocket> iterator = clientsMap.keySet().iterator();
		while(iterator.hasNext()) {
			WebSocket ws = iterator.next();
			WebClientSetModel setModel = clientsMap.get(ws);
			if(setModel.isShowFlag()) {
				String message = logModel.toString();
				// html converting
				message = message.replaceAll("\\r\\n","<br/>");
				message = message.replaceAll("\\n","<br/>");
				message = message.replaceAll("\\t","&nbsp;&nbsp;&nbsp;&nbsp;");
				
				String wrapMessage = WebSocketProtocalConstants.HEADER+WebSocketProtocalConstants.SEPERATOR+WebSocketProtocalConstants.RES_OPERATION_DO+WebSocketProtocalConstants.SEPERATOR+message;
				if(setModel.getShowLoglist() != null && setModel.getShowLoglist().contains(logSocket.toString())) {
					ws.send(wrapMessage);
				}
			}
		}
	}

	@Override
	public void serverStart() {
		start();
	}


	@Override
	public void setContext(Map<String, Object> context) {
		serverContext = context;
	}
}
